/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { basename, dirname } from 'path';
import { readFileSync, readFile, existsSync } from 'fs';
import { URI } from 'vscode-uri';
import { CompilerOptions } from 'typescript';
import { joinPath, isAbsolutePath, extname, dirname as uriDirName } from '../requests';
import { TextDocument } from 'vscode-html-languageservice';
import { HTMLDocument } from './embeddedSupport';
import { Workspace } from './languageModes';

const serverFolder = URI.file(basename(__dirname) === 'dist' ? dirname(__dirname) : dirname(dirname(__dirname))).toString();
let TYPESCRIPT_LIB_SOURCE: string;

if (__dirname.includes('.vscode')) {
	TYPESCRIPT_LIB_SOURCE = joinPath(serverFolder, '../node_modules/typescript/lib');
} else {
	TYPESCRIPT_LIB_SOURCE = joinPath(serverFolder, '../../node_modules/typescript/lib');
}
const JQUERY_PATH = joinPath(serverFolder, 'lib/jquery.d.ts');

interface LibsCache {
	getImportedScripts(document: HTMLDocument): string[];
	getDefaultLibFileName(_options: CompilerOptions): string;
	scriptFileChanged(uri: string): void;
	getScriptVersion(uri: string): string;
	getScriptSnapshot(uri: string): TextDocument;
}
let importedScripts = new Map<string, [string[], string[]]>();
let scriptDocuments = new Map<string, TextDocument>();
export function getLibsManager(workSpace: Workspace): LibsCache {
	return {
		getImportedScripts(document: HTMLDocument): string[] {
			let scripts: [string[], string[]];
			if (importedScripts.has(document.uri)) {
				scripts = importedScripts.get(document.uri)!;
			} else {
				scripts = [[], []];
				scripts[0].push(document.uri, JQUERY_PATH);
				scripts[1].push(document.uri, JQUERY_PATH);
				importedScripts.set(document.uri, scripts);
			}
			let workSpaceFolder = workSpace.folders[0];
			if (!workSpaceFolder) return scripts[1];
			let addedScript = document.importedScripts.filter(e => !scripts[0].includes(e));
			let removedScript = scripts[0].filter((e, idx) => idx > 1 && (!document.importedScripts.includes(e)));
			addedScript.forEach(scriptFile => {
				let extFileName = extname(scriptFile);
				if (extFileName !== '.js' && extFileName !== '.ts') { return; }
				let absScriptFile;
				if (isAbsolutePath(scriptFile)) {
					absScriptFile = joinPath(workSpaceFolder!.uri, scriptFile);
				} else {
					absScriptFile = joinPath(uriDirName(document.uri), scriptFile);
				}
				let absDTSFile = absScriptFile.substring(0, absScriptFile.lastIndexOf('.')) + '.d.ts';
				if (existsSync(URI.parse(absDTSFile).fsPath)) {
					scripts[1].push(absDTSFile);
				} else if (existsSync(URI.parse(absScriptFile).fsPath)) {
					scripts[1].push(absScriptFile);;
				} else {
					return;
				}
				scripts[0].push(scriptFile);
			})
			removedScript.forEach((scriptFile) => {
				let idx = scripts[0].indexOf(scriptFile);
				scripts[0].splice(idx, 1);
				scriptDocuments.delete(scripts[1][idx]);
				scripts[1].splice(idx, 1);
			})
			return scripts[1];
		},
		getDefaultLibFileName(_options: CompilerOptions) {
			return TYPESCRIPT_LIB_SOURCE + "/es9";
		},
		scriptFileChanged(uri: string) {
			if (scriptDocuments.has(uri)) {
				let doc = scriptDocuments.get(uri)!;

				let absFile = URI.parse(uri).fsPath;
				readFile(absFile, undefined, (err, buf) => {
					if (err) {
						let document = TextDocument.create(uri, doc.languageId, 1, "");
						scriptDocuments.set(uri, document);
					} else {
						let document = TextDocument.create(uri, doc.languageId, doc.version + 1, buf.toString());
						scriptDocuments.set(uri, document);
					}
				});
			}
		},
		getScriptVersion(uri: string) {
			let doc = scriptDocuments.get(uri)!;
			return String(doc.version);
		},
		getScriptSnapshot(uri: string) {
			let doc = scriptDocuments.get(uri)!;
			if (!doc) {
				let scriptPath;
				let content;
				scriptPath = URI.parse(uri).fsPath; //from import
				try {
					content = readFileSync(scriptPath).toString();
					let language = extname(uri).toLowerCase() === 'js' ? 'javascript' : 'typescript';
					doc = TextDocument.create(uri, language, 1, content);
					scriptDocuments.set(uri, doc);
				} catch (e) {
					console.log(`Unable to load library ${uri} at ${scriptPath}: ${e.message}`);
					doc = TextDocument.create(uri, "javascript", 1, "");
				}
			}
			return doc;
		}
	}
}
